/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * Frame.java
 *
 * Created on Feb 18, 2010, 8:36:12 PM
 */
package wiiscript;

import java.awt.AWTException;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FileDialog;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.net.URL;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.JFileChooser;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.KeyStroke;
import javax.swing.border.Border;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import javax.swing.event.UndoableEditEvent;
import javax.swing.event.UndoableEditListener;
import javax.swing.text.DefaultEditorKit;
import javax.swing.undo.CannotRedoException;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;
import wiiremotej.WiiRemote;
import wiiremotej.event.WRButtonEvent;

/**
 *
 * @author Evan
 */
public class Frame extends javax.swing.JFrame {

    private Main main;
    private WiiRemoteInterface wiiConnect = new WiiRemoteInterface();
    private boolean detectInput = false;
    private boolean detectOutput = false;
    public static DefaultListModel connectionList = new DefaultListModel();
    private String currentFile = null;
    public static boolean saved = true;
    private Vector<File> recentFiles = new Vector<File>();
    private boolean running = false;

    private UndoManager undo = new UndoManager();
    private UndoAction undoAction = new UndoAction();
    private RedoAction redoAction = new RedoAction();

    private boolean hasFound = false;
    private String lastFind = "";

    /** Creates new form Frame */
    public Frame(Main main) {
        this.main = main;
        addKeyListener(new KeyboardListener());
        addMouseListener(new MouseOutputListener());
        setFocusable(true);       
        getRecentFiles();
        //Pre init settings
        if(Main.getOS() == Main.OS.Mac) {
            System.setProperty("apple.laf.useScreenMenuBar", "true");
            com.apple.eawt.Application macApp = com.apple.eawt.Application.getApplication();
            macApp.addApplicationListener(new com.apple.eawt.ApplicationAdapter() {

                @Override
                public void handleQuit(com.apple.eawt.ApplicationEvent e) {
                    if (!saved) {
                        if (askToSave()) {
                            exit();
                        }
                    } else {
                        exit();
                    }
                }
            });
        }

        initComponents();
        //Post init settings
        if(Main.getOS() == Main.OS.Mac) {
           runButton.putClientProperty("JButton.buttonType", "textured");
           editScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
           fileMenu.remove(exitMenuItem);
           fileMenu.remove(fileSeparator);
           viewHelpMenuItem.setText("WiiScript Help");
           helpMenu.remove(helpSeparator);
           helpMenu.remove(aboutMenuItem);
           newMenuItem.setText("New");
        }
        guiList.setModel(connectionList);
        connectionList.addListDataListener(new ListListener());

        //Drag and drop functionality
        new FileDrop(editPane, new FileDrop.Listener() {
            @Override
            public void filesDropped(File[] files) {
                if(!saved) askToSave();
                open(files[0]);
            }
        });
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        popupMenu = new javax.swing.JPopupMenu();
        cutPopup = new javax.swing.JMenuItem();
        copyPopup = new javax.swing.JMenuItem();
        pastePopup = new javax.swing.JMenuItem();
        deletePopup = new javax.swing.JMenuItem();
        jSeparator3 = new javax.swing.JPopupMenu.Separator();
        selectAllPopup = new javax.swing.JMenuItem();
        jDesktopPane1 = new javax.swing.JDesktopPane();
        runButton = new javax.swing.JToggleButton();
        tabPane = new javax.swing.JTabbedPane();
        jPanel1 = new javax.swing.JPanel();
        editScrollPane = new javax.swing.JScrollPane();
        editPane = new EditorPane();
        debugLabel = new javax.swing.JLabel();
        findPanel = new javax.swing.JPanel();
        findTextField = new javax.swing.JTextField();
        closeFindButton = new javax.swing.JButton();
        jPanel4 = new javax.swing.JPanel();
        wrapArroundBox = new javax.swing.JCheckBox();
        wholeWordBox = new javax.swing.JCheckBox();
        findBackButton = new javax.swing.JButton();
        findForwardButton = new javax.swing.JButton();
        jPanel2 = new javax.swing.JPanel();
        jScrollPane1 = new javax.swing.JScrollPane();
        guiList = new javax.swing.JList();
        detectInputButton = new javax.swing.JButton();
        detectOutputButton = new javax.swing.JButton();
        addButton = new javax.swing.JButton();
        outputLabel = new javax.swing.JLabel();
        inputLabel = new javax.swing.JLabel();
        debugText = new javax.swing.JTextField();
        jPanel3 = new javax.swing.JPanel();
        wiiRemoteButton = new javax.swing.JButton();
        connectLabel = new javax.swing.JLabel();
        jMenuBar1 = new javax.swing.JMenuBar();
        fileMenu = new javax.swing.JMenu();
        newMenuItem = new javax.swing.JMenuItem();
        openMenuItem = new javax.swing.JMenuItem();
        openRecentMenuItem = new javax.swing.JMenu();
        saveMenuItem = new javax.swing.JMenuItem();
        jMenuItem4 = new javax.swing.JMenuItem();
        fileSeparator = new javax.swing.JPopupMenu.Separator();
        exitMenuItem = new javax.swing.JMenuItem();
        editMenu = new javax.swing.JMenu();
        jSeparator2 = new javax.swing.JPopupMenu.Separator();
        cutMenuItem = new javax.swing.JMenuItem(new DefaultEditorKit.CutAction());
        copyMenuItem = new javax.swing.JMenuItem(new DefaultEditorKit.CopyAction());
        pasteMenuItem = new javax.swing.JMenuItem(new DefaultEditorKit.PasteAction());
        deleteMenuItem = new javax.swing.JMenuItem();
        jSeparator5 = new javax.swing.JPopupMenu.Separator();
        jMenuItem9 = new javax.swing.JMenuItem();
        jMenuItem10 = new javax.swing.JMenuItem();
        jSeparator4 = new javax.swing.JPopupMenu.Separator();
        jMenuItem8 = new javax.swing.JMenuItem();
        helpMenu = new javax.swing.JMenu();
        viewHelpMenuItem = new javax.swing.JMenuItem();
        helpSeparator = new javax.swing.JPopupMenu.Separator();
        aboutMenuItem = new javax.swing.JMenuItem();

        cutPopup.setText("Cut");
        cutPopup.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                cutPopupActionPerformed(evt);
            }
        });
        popupMenu.add(cutPopup);

        copyPopup.setText("Copy");
        popupMenu.add(copyPopup);

        pastePopup.setText("Paste");
        popupMenu.add(pastePopup);

        deletePopup.setText("Delete");
        popupMenu.add(deletePopup);
        popupMenu.add(jSeparator3);

        selectAllPopup.setText("Select All");
        popupMenu.add(selectAllPopup);

        setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);
        setTitle("Untitled - WiiScript");
        setMinimumSize(new java.awt.Dimension(401, 360));
        addWindowFocusListener(new java.awt.event.WindowFocusListener() {
            public void windowGainedFocus(java.awt.event.WindowEvent evt) {
            }
            public void windowLostFocus(java.awt.event.WindowEvent evt) {
                formWindowLostFocus(evt);
            }
        });
        addWindowListener(new java.awt.event.WindowAdapter() {
            public void windowClosing(java.awt.event.WindowEvent evt) {
                formWindowClosing(evt);
            }
        });
        addFocusListener(new java.awt.event.FocusAdapter() {
            public void focusLost(java.awt.event.FocusEvent evt) {
                formFocusLost(evt);
            }
        });
        addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyTyped(java.awt.event.KeyEvent evt) {
                formKeyTyped(evt);
            }
            public void keyPressed(java.awt.event.KeyEvent evt) {
                formKeyPressed(evt);
            }
        });

        runButton.setText("Run");
        runButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                runButtonActionPerformed(evt);
            }
        });
        runButton.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyReleased(java.awt.event.KeyEvent evt) {
                runButtonKeyReleased(evt);
            }
        });

        editPane.setStyledDocument(new wiiscript.ColorCodeDoc(this));
        editPane.setComponentPopupMenu(popupMenu);
        editPane.getDocument().addUndoableEditListener(new UndoListener());
        editPane.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mousePressed(java.awt.event.MouseEvent evt) {
                editPaneMousePressed(evt);
            }
            public void mouseReleased(java.awt.event.MouseEvent evt) {
                editPaneMouseReleased(evt);
            }
        });
        editPane.addFocusListener(new java.awt.event.FocusAdapter() {
            public void focusGained(java.awt.event.FocusEvent evt) {
                editPaneFocusGained(evt);
            }
        });
        editPane.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyTyped(java.awt.event.KeyEvent evt) {
                editPaneKeyTyped(evt);
            }
        });
        editScrollPane.setViewportView(editPane);

        debugLabel.setPreferredSize(new java.awt.Dimension(45, 16));

        findTextField.setPreferredSize(new java.awt.Dimension(200, 28));
        findTextField.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                findTextFieldActionPerformed(evt);
            }
        });
        if(Main.getOS() == Main.OS.Mac) {
            findTextField.putClientProperty("JTextField.variant", "search");
            findTextField.putClientProperty("JTextField.Search.FindAction",
                new ActionListener() {
                    public void actionPerformed(ActionEvent evt) {
                        findNext();
                    }
                }
            );
        } else if(Main.getOS() == Main.OS.Windows) {
            findTextField.setPreferredSize(new Dimension(200,20));
        }

        closeFindButton.setText("X");
        if(Main.getOS() == Main.OS.Mac) {
            closeFindButton.putClientProperty("JButton.buttonType", "segmentedRoundRect");
            closeFindButton.putClientProperty("JButton.segmentPosition", "only");
        }
        closeFindButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                closeFindButtonActionPerformed(evt);
            }
        });

        jPanel4.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.CENTER, 0, 0));

        wrapArroundBox.setSelected(true);
        wrapArroundBox.setText("Wrap arround");
        jPanel4.add(wrapArroundBox);

        wholeWordBox.setSelected(true);
        wholeWordBox.setText("Whole word");
        wholeWordBox.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                wholeWordBoxActionPerformed(evt);
            }
        });
        jPanel4.add(wholeWordBox);

        findBackButton.setText("<");
        if(Main.getOS() == Main.OS.Mac) {
            findBackButton.putClientProperty("JButton.buttonType", "segmentedRoundRect");
            findBackButton.putClientProperty("JButton.segmentPosition", "first");
        }
        jPanel4.add(findBackButton);

        findForwardButton.setText(">");
        if(Main.getOS() == Main.OS.Mac) {
            findForwardButton.putClientProperty("JButton.buttonType", "segmentedRoundRect");
            findForwardButton.putClientProperty("JButton.segmentPosition", "last");
        }
        findForwardButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                findForwardButtonActionPerformed(evt);
            }
        });
        jPanel4.add(findForwardButton);

        findPanel.setVisible(false);

        javax.swing.GroupLayout findPanelLayout = new javax.swing.GroupLayout(findPanel);
        findPanel.setLayout(findPanelLayout);
        findPanelLayout.setHorizontalGroup(
            findPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(findPanelLayout.createSequentialGroup()
                .addComponent(jPanel4, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(findTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 171, Short.MAX_VALUE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(closeFindButton))
        );
        findPanelLayout.setVerticalGroup(
            findPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(findPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                .addComponent(findTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addComponent(closeFindButton))
            .addComponent(jPanel4, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
        );

        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
        jPanel1.setLayout(jPanel1Layout);
        jPanel1Layout.setHorizontalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(debugLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 480, Short.MAX_VALUE)
            .addComponent(findPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
            .addComponent(editScrollPane, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 480, Short.MAX_VALUE)
        );
        jPanel1Layout.setVerticalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
                .addComponent(findPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(editScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 158, Short.MAX_VALUE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(debugLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
        );

        tabPane.addTab("Script", jPanel1);

        guiList.setFont(new java.awt.Font("Monospaced", 0, 11)); // NOI18N
        guiList.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyPressed(java.awt.event.KeyEvent evt) {
                guiListKeyPressed(evt);
            }
        });
        jScrollPane1.setViewportView(guiList);

        detectInputButton.setText("Detect Input");
        detectInputButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                detectInputButtonActionPerformed(evt);
            }
        });

        detectOutputButton.setText("Detect Output");
        detectOutputButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                detectOutputButtonActionPerformed(evt);
            }
        });

        addButton.setText("Add");
        addButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                addButtonActionPerformed(evt);
            }
        });

        outputLabel.setText("None");

        inputLabel.setText("None");

        javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
        jPanel2.setLayout(jPanel2Layout);
        jPanel2Layout.setHorizontalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 480, Short.MAX_VALUE)
            .addGroup(jPanel2Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
                    .addComponent(detectInputButton, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(detectOutputButton, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                .addGap(18, 18, 18)
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(jPanel2Layout.createSequentialGroup()
                        .addComponent(inputLabel)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 265, Short.MAX_VALUE)
                        .addComponent(addButton))
                    .addComponent(outputLabel))
                .addContainerGap())
        );
        jPanel2Layout.setVerticalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel2Layout.createSequentialGroup()
                .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 135, Short.MAX_VALUE)
                .addGap(11, 11, 11)
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(detectOutputButton)
                    .addComponent(outputLabel))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(detectInputButton)
                    .addComponent(addButton)
                    .addComponent(inputLabel))
                .addContainerGap())
        );

        tabPane.addTab("GUI", jPanel2);

        debugText.setVisible(false);
        debugText.setOpaque(false);
        debugText.setEditable(false);
        debugText.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        debugText.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 15));
        debugText.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                debugTextActionPerformed(evt);
            }
        });

        wiiRemoteButton.setText("Connect WiiRemote");
        wiiRemoteButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                wiiRemoteButtonActionPerformed(evt);
            }
        });

        connectLabel.setForeground(new java.awt.Color(255, 0, 0));
        connectLabel.setText("Not Connected ");

        javax.swing.GroupLayout jPanel3Layout = new javax.swing.GroupLayout(jPanel3);
        jPanel3.setLayout(jPanel3Layout);
        jPanel3Layout.setHorizontalGroup(
            jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel3Layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(wiiRemoteButton)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 263, Short.MAX_VALUE)
                .addComponent(connectLabel)
                .addContainerGap())
        );
        jPanel3Layout.setVerticalGroup(
            jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel3Layout.createSequentialGroup()
                .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(wiiRemoteButton)
                    .addComponent(connectLabel))
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        fileMenu.setText("File");
        fileMenu.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                fileMenuActionPerformed(evt);
            }
        });

        newMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N,
            Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
    newMenuItem.setText("New...");
    newMenuItem.addActionListener(new java.awt.event.ActionListener() {
        public void actionPerformed(java.awt.event.ActionEvent evt) {
            newMenuItemActionPerformed(evt);
        }
    });
    fileMenu.add(newMenuItem);

    openMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_O,
        Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
openMenuItem.setText("Open...");
openMenuItem.addActionListener(new java.awt.event.ActionListener() {
    public void actionPerformed(java.awt.event.ActionEvent evt) {
        openMenuItemActionPerformed(evt);
    }
    });
    fileMenu.add(openMenuItem);

    openRecentMenuItem.setText("Open Recent");

    for(File s : recentFiles) {
        JMenuItem item = new JMenuItem(s.getName());
        item.addActionListener(new RecentFilesListener(s));
        openRecentMenuItem.add(item);
    }

    fileMenu.add(openRecentMenuItem);

    saveMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_S,
        Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
saveMenuItem.setText("Save");
saveMenuItem.addActionListener(new java.awt.event.ActionListener() {
    public void actionPerformed(java.awt.event.ActionEvent evt) {
        saveMenuItemActionPerformed(evt);
    }
    });
    fileMenu.add(saveMenuItem);

    jMenuItem4.setText("Save As...");
    jMenuItem4.addActionListener(new java.awt.event.ActionListener() {
        public void actionPerformed(java.awt.event.ActionEvent evt) {
            jMenuItem4ActionPerformed(evt);
        }
    });
    fileMenu.add(jMenuItem4);
    fileMenu.add(fileSeparator);

    exitMenuItem.setText("Exit");
    exitMenuItem.addActionListener(new java.awt.event.ActionListener() {
        public void actionPerformed(java.awt.event.ActionEvent evt) {
            exitMenuItemActionPerformed(evt);
        }
    });
    fileMenu.add(exitMenuItem);

    jMenuBar1.add(fileMenu);

    editMenu.setText("Edit");
    editMenu.add(undoAction);
    editMenu.add(redoAction);
    editMenu.add(jSeparator2);

    cutMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_X, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
    cutMenuItem.setText("Cut");
    cutMenuItem.setEnabled(false);
    editMenu.add(cutMenuItem);

    copyMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_C, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
    copyMenuItem.setText("Copy");
    copyMenuItem.setEnabled(false);
    editMenu.add(copyMenuItem);

    pasteMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_V, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
    pasteMenuItem.setText("Paste");
    pasteMenuItem.setEnabled(false);
    editMenu.add(pasteMenuItem);

    deleteMenuItem.setText("Delete");
    deleteMenuItem.setEnabled(false);
    deleteMenuItem.addActionListener(new java.awt.event.ActionListener() {
        public void actionPerformed(java.awt.event.ActionEvent evt) {
            deleteMenuItemActionPerformed(evt);
        }
    });
    editMenu.add(deleteMenuItem);
    editMenu.add(jSeparator5);

    jMenuItem9.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
    jMenuItem9.setText("Find");
    jMenuItem9.addActionListener(new java.awt.event.ActionListener() {
        public void actionPerformed(java.awt.event.ActionEvent evt) {
            jMenuItem9ActionPerformed(evt);
        }
    });
    editMenu.add(jMenuItem9);

    jMenuItem10.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_R, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
    jMenuItem10.setText("Replace");
    jMenuItem10.addActionListener(new java.awt.event.ActionListener() {
        public void actionPerformed(java.awt.event.ActionEvent evt) {
            jMenuItem10ActionPerformed(evt);
        }
    });
    editMenu.add(jMenuItem10);
    editMenu.add(jSeparator4);

    jMenuItem8.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_A, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
    jMenuItem8.setText("Select All");
    jMenuItem8.addActionListener(new java.awt.event.ActionListener() {
        public void actionPerformed(java.awt.event.ActionEvent evt) {
            jMenuItem8ActionPerformed(evt);
        }
    });
    editMenu.add(jMenuItem8);

    jMenuBar1.add(editMenu);

    helpMenu.setText("Help");

    viewHelpMenuItem.setText("View Help");
    helpMenu.add(viewHelpMenuItem);
    helpMenu.add(helpSeparator);

    aboutMenuItem.setText("About WiiScript");
    aboutMenuItem.addActionListener(new java.awt.event.ActionListener() {
        public void actionPerformed(java.awt.event.ActionEvent evt) {
            aboutMenuItemActionPerformed(evt);
        }
    });
    helpMenu.add(aboutMenuItem);

    jMenuBar1.add(helpMenu);

    setJMenuBar(jMenuBar1);

    javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
    getContentPane().setLayout(layout);
    layout.setHorizontalGroup(
        layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addGroup(layout.createSequentialGroup()
            .addContainerGap()
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addComponent(jPanel3, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addComponent(tabPane, javax.swing.GroupLayout.DEFAULT_SIZE, 485, Short.MAX_VALUE)
                .addGroup(layout.createSequentialGroup()
                    .addComponent(runButton, javax.swing.GroupLayout.PREFERRED_SIZE, 103, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addGap(18, 18, 18)
                    .addComponent(debugText, javax.swing.GroupLayout.DEFAULT_SIZE, 364, Short.MAX_VALUE)))
            .addContainerGap())
    );
    layout.setVerticalGroup(
        layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addGroup(layout.createSequentialGroup()
            .addContainerGap()
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                .addComponent(debugText, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addComponent(runButton))
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
            .addComponent(tabPane, javax.swing.GroupLayout.DEFAULT_SIZE, 242, Short.MAX_VALUE)
            .addGap(4, 4, 4)
            .addComponent(jPanel3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
    );

    pack();
    }// </editor-fold>//GEN-END:initComponents

    private void formKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_formKeyPressed

    }//GEN-LAST:event_formKeyPressed

    private void formKeyTyped(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_formKeyTyped

    }//GEN-LAST:event_formKeyTyped

    private void formWindowLostFocus(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowLostFocus
        
    }//GEN-LAST:event_formWindowLostFocus

    private void formFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_formFocusLost
        detectOutput = false;
        detectInput = false;
        detectOutputButton.setEnabled(true);
        detectInputButton.setEnabled(true);
        addButton.setEnabled(true);
    }//GEN-LAST:event_formFocusLost

    private void exitMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_exitMenuItemActionPerformed
        if(!saved) {
            if(askToSave()) {
                exit();
            }
        } else {
            exit();
        }
    }//GEN-LAST:event_exitMenuItemActionPerformed

    private void openMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openMenuItemActionPerformed
        if(!saved) askToSave();    
        if(Main.getOS() == Main.OS.Mac) {
            FileDialog fd = new FileDialog(this, "Open", FileDialog.LOAD);
            fd.setFilenameFilter(new FilenameFilter() {
               @Override
               public boolean accept(File dir, String name) {
                   name = name.toLowerCase();
                   return (name.endsWith(".txt") || name.endsWith(".pie"));
               }
            });
            fd.setVisible(true);
            String fileName = fd.getDirectory() + System.getProperty("file.separator") + fd.getFile();
            File file = new File(fileName);
            if(file.exists()) {
                open(file);
            }
        } else {
            JFileChooser fc = new JFileChooser();
            fc.addChoosableFileFilter(new ScriptFilter());
            int returnVal = fc.showOpenDialog(this);
            if (returnVal == JFileChooser.APPROVE_OPTION) {
                File file = fc.getSelectedFile();
                open(file);
            }
        }
        
    }//GEN-LAST:event_openMenuItemActionPerformed

    private void fileMenuActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_fileMenuActionPerformed
        
    }//GEN-LAST:event_fileMenuActionPerformed

    private void saveMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveMenuItemActionPerformed
        save();
    }//GEN-LAST:event_saveMenuItemActionPerformed

    private void jMenuItem4ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem4ActionPerformed
        saveAs();
    }//GEN-LAST:event_jMenuItem4ActionPerformed

    private void newMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newMenuItemActionPerformed
        if(saved || askToSave()) {
            clear();
        }
    }//GEN-LAST:event_newMenuItemActionPerformed

    private void cutPopupActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cutPopupActionPerformed
        // TODO add your handling code here:
    }//GEN-LAST:event_cutPopupActionPerformed

    private void formWindowClosing(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosing
        if(!saved) {
            if(askToSave()) {
                exit();
            }
        } else {
            exit();
        }
    }//GEN-LAST:event_formWindowClosing

    private void wiiRemoteButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_wiiRemoteButtonActionPerformed
        if(wiiRemoteButton.getText().equals("Connect WiiRemote ")) {
            wiiConnect.connect(new wiiListener());
            connectLabel.setText("Trying to connect... ");
            connectLabel.setForeground(Color.black);
            wiiRemoteButton.setEnabled(false);
        } else {
            wiiConnect.disconnect();
            connectLabel.setText("Not Connected ");
            connectLabel.setForeground(Color.red);
            wiiRemoteButton.setEnabled(true);
            wiiRemoteButton.setText("Connect WiiRemote ");
        }
    }//GEN-LAST:event_wiiRemoteButtonActionPerformed

    private void addButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addButtonActionPerformed
        String output = outputLabel.getText();
        String input = inputLabel.getText();
        if(!output.equals("None") && !input.equals("None")) {
            String line = "keyboard." + output + " = wiiremote." + input;
            connectionList.addElement(line);
            ((EditorPane)editPane).addLine(line);
            inputLabel.setText("None");
        }
}//GEN-LAST:event_addButtonActionPerformed

    private void detectOutputButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_detectOutputButtonActionPerformed
        detectOutput = true;
        detectInputButton.setEnabled(false);
        detectOutputButton.setEnabled(false);
        addButton.setEnabled(false);
        requestFocus();
}//GEN-LAST:event_detectOutputButtonActionPerformed

    private void detectInputButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_detectInputButtonActionPerformed
        if(connectLabel.getText().equals("Not Connected ")) {
            JOptionPane.showMessageDialog(this, "Please make sure your WiiRemote is connected.",
                    "Cannot find WiiRemote", JOptionPane.ERROR_MESSAGE);
            return;
        }
        detectInput = true;
        detectInputButton.setEnabled(false);
        detectOutputButton.setEnabled(false);
        addButton.setEnabled(false);
        requestFocus();
}//GEN-LAST:event_detectInputButtonActionPerformed

    private void guiListKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_guiListKeyPressed
        if(evt.getKeyCode() == KeyEvent.VK_DELETE || evt.getKeyCode() == KeyEvent.VK_BACK_SPACE) {
            int index = guiList.getSelectedIndex();
            if(index > -1) {
                ((EditorPane)editPane).removeLine((String)connectionList.getElementAt(index));
                connectionList.remove(index);
            }
        }
}//GEN-LAST:event_guiListKeyPressed

    private void editPaneKeyTyped(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_editPaneKeyTyped
        hasFound = false;
}//GEN-LAST:event_editPaneKeyTyped

    private void editPaneMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_editPaneMouseReleased
        if(editPane.getSelectedText() == null) {
            cutMenuItem.setEnabled(false);
            copyMenuItem.setEnabled(false);
            deleteMenuItem.setEnabled(false);
        } else {
            cutMenuItem.setEnabled(true);
            copyMenuItem.setEnabled(true);
            deleteMenuItem.setEnabled(true);
        }
}//GEN-LAST:event_editPaneMouseReleased

    private void editPaneMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_editPaneMousePressed

}//GEN-LAST:event_editPaneMousePressed

    private void runButtonKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_runButtonKeyReleased

}//GEN-LAST:event_runButtonKeyReleased

    private void runButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_runButtonActionPerformed
        if (runButton.isSelected()) {
            debugText.setVisible(true);
            runButton.setText("Stop");
            editPane.setEnabled(false);
            tabPane.setSelectedIndex(0);
            debugText.setText("Debug: 0.00");
            main.run(editPane.getText());
            running = true;
            undoAction.setEnabled(false);
            redoAction.setEnabled(false);
        } else {
            debugText.setVisible(false);
            runButton.setText("Run");
            editPane.setEnabled(true);
            main.stop();
            running = false;
            if(undo.canUndo()) undoAction.setEnabled(true);
            if(undo.canRedo()) redoAction.setEnabled(true);
        }
}//GEN-LAST:event_runButtonActionPerformed

    private void debugTextActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_debugTextActionPerformed
        // TODO add your handling code here:
    }//GEN-LAST:event_debugTextActionPerformed

    private void editPaneFocusGained(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_editPaneFocusGained

    }//GEN-LAST:event_editPaneFocusGained

    private void deleteMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteMenuItemActionPerformed
        try {
            new Robot().keyPress(KeyEvent.VK_DELETE);
            new Robot().keyRelease(KeyEvent.VK_DELETE);
        } catch (AWTException ex) {
            Logger.getLogger(Frame.class.getName()).log(Level.SEVERE, null, ex);
        }
    }//GEN-LAST:event_deleteMenuItemActionPerformed

    private void jMenuItem8ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem8ActionPerformed
        editPane.setSelectionStart(0);
        editPane.setSelectionEnd(editPane.getText().length());
    }//GEN-LAST:event_jMenuItem8ActionPerformed

    private void jMenuItem9ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem9ActionPerformed
        findPanel.setVisible(true);
        findTextField.requestFocus();
        jPanel1.validate();
    }//GEN-LAST:event_jMenuItem9ActionPerformed

    private void findTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_findTextFieldActionPerformed
        findNext();
    }//GEN-LAST:event_findTextFieldActionPerformed

    private void closeFindButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_closeFindButtonActionPerformed
        findPanel.setVisible(false);
        jPanel1.validate();
    }//GEN-LAST:event_closeFindButtonActionPerformed

    private void findForwardButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_findForwardButtonActionPerformed
        findNext();
    }//GEN-LAST:event_findForwardButtonActionPerformed

    private void jMenuItem10ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem10ActionPerformed
        ReplaceDialog replaceD = new ReplaceDialog(this, false);
        replaceD.setVisible(true);
    }//GEN-LAST:event_jMenuItem10ActionPerformed

    private void wholeWordBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_wholeWordBoxActionPerformed
        // TODO add your handling code here:
    }//GEN-LAST:event_wholeWordBoxActionPerformed

    private void aboutMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_aboutMenuItemActionPerformed
        AboutDialog about = new AboutDialog(this, true);
        about.setVisible(true);
    }//GEN-LAST:event_aboutMenuItemActionPerformed

    private void findNext() {
        String currentFind = findTextField.getText();
        if(!currentFind.equals(lastFind)) {
            hasFound = false;
        } else {
            hasFound = true;
        }
        if(currentFind.equals("")) return; //Don't search if search box is empty
        if(!hasFound) {
            ((EditorPane)editPane).find(currentFind, wholeWordBox.isSelected());
            lastFind = currentFind;
            hasFound = true;
        }
        ((EditorPane)editPane).findNext();
    }
    private void save() {
        if(currentFile == null) {
            saveAs();
        } else {
            try {
                BufferedWriter writer = new BufferedWriter(new FileWriter(new File(currentFile)));
                writer.append(editPane.getText());
                writer.close();
                saved = true;
                getRootPane().putClientProperty("Window.documentModified", "false");
            } catch (IOException ex) {
                Logger.getLogger(Frame.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
    private void saveAs() {
        File file = null;
        if(Main.getOS() == Main.OS.Mac) {
            FileDialog fd = new FileDialog(this, "Save", FileDialog.SAVE);
            fd.setVisible(true);
            if(fd.getFile() != null) {
                file = new File(fd.getFile());
            }
        } else {
            JFileChooser fc = new JFileChooser();
            int result = fc.showSaveDialog(this);
            if(result == JFileChooser.APPROVE_OPTION) {
                file = fc.getSelectedFile();
            }
        }
        if(file != null) {
           try {
            String fileName = file.getPath();
            if(!fileName.contains(".")) {
                fileName += ".PIE";
            }
            currentFile = fileName;
            this.setTitle(file.getName() + " - WiiScript");
            if(file.exists() && Main.getOS() != Main.OS.Mac) {
                int r = JOptionPane.showConfirmDialog(this,
                        file.getName() + " already exists.\nDo you want to replace it?",
                        "Confirm Save As", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
                if(r == JOptionPane.YES_OPTION) {
                    BufferedWriter writer = new BufferedWriter(new FileWriter(new File(fileName)));
                    writer.append(editPane.getText());
                    writer.close();
                } else {
                    saveAs();
                }
            }
        } catch (IOException ex) {
            Logger.getLogger(Frame.class.getName()).log(Level.SEVERE, null, ex);
        }
        }
    }
    private boolean askToSave() {
        String name;
        if(currentFile == null) name = "Untitled";
        else name = new File(currentFile).getName();
        Object[] options = {"Save", "Don't Save", "Cancel"};
        int result = 0;
        if(Main.getOS() == Main.OS.Mac) {
           result = MacSheet.showOptionDialog(this, "Do you want to save the changes you made in the document \"" + name + "\"?",
                    "Your changes will be lost if you don't save them.",
                    JOptionPane.YES_NO_CANCEL_OPTION,
                    JOptionPane.QUESTION_MESSAGE);
        } else {
           result = JOptionPane.showOptionDialog(this, "Do you want to save the changes you made in\nthe document \"" + name + "\"?",
                "WiiScript", JOptionPane.YES_NO_CANCEL_OPTION,
                JOptionPane.PLAIN_MESSAGE, null, options, options[0]);
        }
        if(result == JOptionPane.YES_OPTION) {
            save();
            return true;
        } else if(result == JOptionPane.NO_OPTION) {
            return true;
        } else {
            return false;
        }
    }
    private void open(File file) {
            String fileName = file.getName().toLowerCase();
            if(!(fileName.endsWith(".txt") || fileName.endsWith(".pie"))) {
                System.out.println("Invalid file type: " + file.getAbsolutePath());
                JOptionPane.showMessageDialog(this, "The file: " + file + " could not be opend.\nFiles must be of the type *.txt or *.pie.",
                    "Invalid File Type.", JOptionPane.ERROR_MESSAGE);
                return;
            }
        try {
            BufferedReader reader = new BufferedReader(new FileReader(file));
            currentFile = file.getPath();
            setTitle(file.getName() + " - WiiScript");
            String text = "";
            String line;
            while((line = reader.readLine()) != null) {
                text += "\n" + line;
            }
            reader.close();
            text = text.replaceFirst("\\n", "");
            tabPane.setSelectedIndex(0);
            editPane.setText(text);
            addRecentFile(file);
        } catch (FileNotFoundException ex) {
            Logger.getLogger(Frame.class.getName()).log(Level.SEVERE, null, ex);
            JOptionPane.showMessageDialog(this, "The file: " + file + " could not be found.\nThe file may have been moved or deleted.",
                    "File not found.", JOptionPane.ERROR_MESSAGE);
        } catch (IOException ex) {
            Logger.getLogger(Frame.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    private void clear() {
        editPane.setText("");
            currentFile = null;
            setTitle("Untitled - WiiScript");
            saved = true;
            getRootPane().putClientProperty("Window.documentModified", "false");
    }
    private void getRecentFiles() {
        try {
            URL fileURL = getClass().getResource("../res/recentFiles.txt");
            BufferedReader reader = new BufferedReader(new FileReader(fileURL.getPath()));
            String line;
            while((line = reader.readLine()) != null) {
                recentFiles.add(new File(line));
            }
            reader.close();
        } catch (FileNotFoundException ex) {
            Logger.getLogger(Frame.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(Frame.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    private void addRecentFile(File file) {
        if(!recentFiles.contains(file)) {
            recentFiles.add(0, file);
        } else {
            recentFiles.remove(file);
            recentFiles.add(0, file);
        }
        if(recentFiles.size() > 5) {
            recentFiles.remove(5);
        }
        openRecentMenuItem.removeAll();
        for(File s : recentFiles) {
            JMenuItem item = new JMenuItem(s.getName());
            item.addActionListener(new RecentFilesListener(s));
            openRecentMenuItem.add(item);
        }
    }
    private void exit() {
        try {
            URL fileURL = getClass().getResource("../res/recentFiles.txt");
            FileWriter writer = new FileWriter(fileURL.getPath());
            for(File s : recentFiles) {
                writer.append(s.getPath() + "\n");
            }
            writer.close();
            System.exit(0);
        } catch (IOException ex) {
            Logger.getLogger(Frame.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    public void setDebug(String text) {
        if(!debugText.getText().equals("Debug: " + text)) {
            debugText.setText("Debug: " + text);
        }
    }
    public void setError(String error) {
        debugLabel.setText(error);
        debugText.setVisible(false);
        runButton.setText("Run");
        editPane.setEnabled(true);
        runButton.setSelected(false);
        main.stop();
        debugLabel.repaint();
    }
    private class wiiListener implements WiiConnectedListener {
        @Override
        public void actionPerformed(boolean status) {
            if(status) {
                connectLabel.setText("Connected");
                connectLabel.setForeground(Color.green);
                wiiRemoteButton.setText("Disconnect WiiRemote");
                WiiRemote remote = wiiConnect.getRemote();
                main.setRemote(remote);
                remote.addWiiRemoteListener(new ButtonListener());
            } else {
                connectLabel.setText("Not Connected");
                connectLabel.setForeground(Color.red);
            }
            wiiRemoteButton.setEnabled(true);
        }

    }
    private class ButtonListener extends WiiRemoteAdapter {
        @Override
        public void buttonInputReceived(WRButtonEvent evt) {
            if(detectInput) {
                detectInput = false;
                detectInputButton.setEnabled(true);
                detectOutputButton.setEnabled(true);
                addButton.setEnabled(true);
                if(evt.isPressed(WRButtonEvent.A)) {
                    inputLabel.setText("A");
                } else if(evt.isPressed(WRButtonEvent.B)) {
                    inputLabel.setText("B");
                } else if(evt.isPressed(WRButtonEvent.UP)) {
                    inputLabel.setText("UP");
                } else if(evt.isPressed(WRButtonEvent.DOWN)) {
                    inputLabel.setText("Down");
                } else if(evt.isPressed(WRButtonEvent.LEFT)) {
                    inputLabel.setText("Left");
                } else if(evt.isPressed(WRButtonEvent.RIGHT)) {
                    inputLabel.setText("Right");
                } else if(evt.isPressed(WRButtonEvent.MINUS)) {
                    inputLabel.setText("Minus");
                } else if(evt.isPressed(WRButtonEvent.HOME)) {
                    inputLabel.setText("Home");
                } else if(evt.isPressed(WRButtonEvent.PLUS)) {
                    inputLabel.setText("Plus");
                } else if(evt.isPressed(WRButtonEvent.ONE)) {
                    inputLabel.setText("One");
                } else if(evt.isPressed(WRButtonEvent.TWO)) {
                    inputLabel.setText("Two");
                }
            }
        }
    }
    private class KeyboardListener implements KeyListener {
        public void keyTyped(KeyEvent e) {
        }

        public void keyPressed(KeyEvent e) {
            if(detectOutput) {
                detectOutput = false;
                detectInputButton.setEnabled(true);
                detectOutputButton.setEnabled(true);
                addButton.setEnabled(true);
                outputLabel.setText(KeyEvent.getKeyText(e.getKeyCode()));
            }
        }

        public void keyReleased(KeyEvent e) {
        }
    }
    private class MouseOutputListener implements MouseListener {
        @Override
        public void mouseClicked(MouseEvent e) {
            if(detectOutput) {
                detectOutput = false;
                detectInputButton.setEnabled(true);
                detectOutputButton.setEnabled(true);
                addButton.setEnabled(true);
                outputLabel.setText(MouseEvent.getMouseModifiersText(e.getModifiers()));
            }
        }
        @Override
        public void mousePressed(MouseEvent e) {
        }
        @Override
        public void mouseReleased(MouseEvent e) {
        }
        @Override
        public void mouseEntered(MouseEvent e) {
        }
        @Override
        public void mouseExited(MouseEvent e) {
        }
    }
    private class ListListener implements ListDataListener {
        public void intervalAdded(ListDataEvent e) {
            guiList.repaint();
        }

        public void intervalRemoved(ListDataEvent e) {
            guiList.repaint();
        }

        public void contentsChanged(ListDataEvent e) {
            guiList.repaint();
        }
    }
    private class RecentFilesListener implements ActionListener {
        private File file;
        public RecentFilesListener(File file) {
            this.file = file;
        }
        public void actionPerformed(ActionEvent e) {
            if(!saved) askToSave();
            Frame.this.open(file);
        }
    }
    class UndoAction extends AbstractAction {
        public UndoAction() {
            super("Undo");
            setEnabled(false);
            putValue(Action.ACCELERATOR_KEY,
                    KeyStroke.getKeyStroke(KeyEvent.VK_Z,
                    Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            if(running) return;
            try {
                undo.undo();
            } catch (CannotUndoException ex) {
                System.out.println("Unable to undo: " + ex);
                ex.printStackTrace();
            }
            updateUndoState();
            redoAction.updateRedoState();
        }

        protected void updateUndoState() {
            if (undo.canUndo()) {
                setEnabled(true);
                putValue(Action.NAME, undo.getUndoPresentationName());
            } else {
                setEnabled(false);
                putValue(Action.NAME, "Undo");
            }
        }
    }

    class RedoAction extends AbstractAction {
        public RedoAction() {
            super("Redo");
            setEnabled(false);
            putValue(Action.ACCELERATOR_KEY, 
                    KeyStroke.getKeyStroke(KeyEvent.VK_Z,
                    Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() + ActionEvent.SHIFT_MASK));
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            if(running) return;
            try {
                undo.redo();
            } catch (CannotRedoException ex) {
                System.out.println("Unable to redo: " + ex);
                ex.printStackTrace();
            }
            updateRedoState();
            undoAction.updateUndoState();
        }

        protected void updateRedoState() {
            if (undo.canRedo()) {
                setEnabled(true);
                putValue(Action.NAME, undo.getRedoPresentationName());
            } else {
                setEnabled(false);
                putValue(Action.NAME, "Redo");
            }
        }
    }
    private class UndoListener implements UndoableEditListener {
        @Override
        public void undoableEditHappened(UndoableEditEvent e) {
            String changeName = e.getEdit().getPresentationName();
            if(changeName.equals("addition") || changeName.equals("deletion")) {
                undo.addEdit(e.getEdit());
                undoAction.updateUndoState();
                redoAction.updateRedoState();
            }
        }
    }


    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JMenuItem aboutMenuItem;
    private javax.swing.JButton addButton;
    private javax.swing.JButton closeFindButton;
    private javax.swing.JLabel connectLabel;
    private javax.swing.JMenuItem copyMenuItem;
    private javax.swing.JMenuItem copyPopup;
    private javax.swing.JMenuItem cutMenuItem;
    private javax.swing.JMenuItem cutPopup;
    private javax.swing.JLabel debugLabel;
    private javax.swing.JTextField debugText;
    private javax.swing.JMenuItem deleteMenuItem;
    private javax.swing.JMenuItem deletePopup;
    private javax.swing.JButton detectInputButton;
    private javax.swing.JButton detectOutputButton;
    private javax.swing.JMenu editMenu;
    private javax.swing.JTextPane editPane;
    private javax.swing.JScrollPane editScrollPane;
    private javax.swing.JMenuItem exitMenuItem;
    private javax.swing.JMenu fileMenu;
    private javax.swing.JPopupMenu.Separator fileSeparator;
    private javax.swing.JButton findBackButton;
    private javax.swing.JButton findForwardButton;
    private javax.swing.JPanel findPanel;
    private javax.swing.JTextField findTextField;
    private javax.swing.JList guiList;
    private javax.swing.JMenu helpMenu;
    private javax.swing.JPopupMenu.Separator helpSeparator;
    private javax.swing.JLabel inputLabel;
    private javax.swing.JDesktopPane jDesktopPane1;
    private javax.swing.JMenuBar jMenuBar1;
    private javax.swing.JMenuItem jMenuItem10;
    private javax.swing.JMenuItem jMenuItem4;
    private javax.swing.JMenuItem jMenuItem8;
    private javax.swing.JMenuItem jMenuItem9;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JPanel jPanel3;
    private javax.swing.JPanel jPanel4;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JPopupMenu.Separator jSeparator2;
    private javax.swing.JPopupMenu.Separator jSeparator3;
    private javax.swing.JPopupMenu.Separator jSeparator4;
    private javax.swing.JPopupMenu.Separator jSeparator5;
    private javax.swing.JMenuItem newMenuItem;
    private javax.swing.JMenuItem openMenuItem;
    private javax.swing.JMenu openRecentMenuItem;
    private javax.swing.JLabel outputLabel;
    private javax.swing.JMenuItem pasteMenuItem;
    private javax.swing.JMenuItem pastePopup;
    private javax.swing.JPopupMenu popupMenu;
    private javax.swing.JToggleButton runButton;
    private javax.swing.JMenuItem saveMenuItem;
    private javax.swing.JMenuItem selectAllPopup;
    private javax.swing.JTabbedPane tabPane;
    private javax.swing.JMenuItem viewHelpMenuItem;
    private javax.swing.JCheckBox wholeWordBox;
    private javax.swing.JButton wiiRemoteButton;
    private javax.swing.JCheckBox wrapArroundBox;
    // End of variables declaration//GEN-END:variables
}
